package com.topscomm.base.calendar;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.topscomm.base.BaseSystemConst.PeroidTypeEnum;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.pub.util.StringBufferProxy;
import com.topscomm.pub.util.StringUtil;
import com.topscomm.tap.common.ParameterCache;

/**
 * 周期日期生成
 * 
 * @description:
 * @author: donghang
 * @date: 2020年10月29日上午10:09:14
 * @modify:
 */
@Component
public class PeroidRepeatService {
	/**
	 * @description:
	 * @param repeatParams
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午10:10:32
	 * @modify:
	 */
	public List<Map<String, Object>> getPeroidDays(PeroidParams repeatParams) {
		if (StringUtil.isEmpty(repeatParams.getBeginTime())
				|| (repeatParams.getEndtype() == 1 && StringUtil.isEmpty(repeatParams.getEndTime()))
				|| (repeatParams.getEndtype() == 2 && repeatParams.getTimes() == 0)) {
			throw new ServiceException("参数不完整");
		}
		List<Map<String, Object>> dates = null;
		switch (repeatParams.getPeriodType()) {
		case PeroidTypeEnum.Day:
			dates = this.repeatByDay(repeatParams);
			break;
		case PeroidTypeEnum.Week:
			dates = this.repeatByWeek(repeatParams);
			break;
		case PeroidTypeEnum.Month:
			dates = this.repeatByMonth(repeatParams);
			break;
		default:
			return null;
		}
		return dates;
	}

	/**
	 * 周期类型为天
	 * 
	 * @description:
	 * @param repeatParams
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午10:18:02
	 * @modify:
	 */
	private List<Map<String, Object>> repeatByDay(PeroidParams repeatParams) {
		int maxCount = ParameterCache.getIntValue("PeroidMaxCount", 100);
		List<Map<String, Object>> localDates = new ArrayList<>();
		LocalDate startsOn = LocalDate.parse(repeatParams.getBeginTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		localDates.add(this.getData(repeatParams, startsOn));
		if (repeatParams.getEndtype() == 2) {// 设置次数
			if (repeatParams.getTimes() > maxCount) {
				throw new RuntimeException("周期最多允许生成" + maxCount + "次");
			}
			for (int i = 1; i < repeatParams.getTimes(); i++) {
				LocalDate nextDate = startsOn.plusDays(repeatParams.getPeriodFrequency());
				localDates.add(this.getData(repeatParams, nextDate));
				startsOn = nextDate;
			}
		} else {// 结束时间生成
			LocalDate endsOn = LocalDate.parse(repeatParams.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			endsOn = endsOn.plusDays(1);
			LocalDate nextDate = startsOn;
			int count = 0;
			while (nextDate.plusDays(repeatParams.getPeriodFrequency()).isBefore(endsOn)) {
				nextDate = nextDate.plusDays(repeatParams.getPeriodFrequency());
				localDates.add(this.getData(repeatParams, nextDate));
				count++;
				if (count > maxCount) {
					throw new RuntimeException("周期最多允许生成" + maxCount + "次");
				}
			}
		}
		return localDates;
	}

	/**
	 * 周期类型周
	 * 
	 * @description:
	 * @param repeatParams
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午10:18:24
	 * @modify:
	 */
	private List<Map<String, Object>> repeatByWeek(PeroidParams repeatParams) {
		List<Map<String, Object>> localDates = new ArrayList<>();
		LocalDate startsOn = LocalDate.parse(repeatParams.getBeginTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		// 周几
		int weekNum = repeatParams.getDaySequence();
		// 得到开始日期是星期几
		int now = startsOn.getDayOfWeek().getValue();
		// 偏移天数
		int dayOffset = weekNum - now;
		if (dayOffset < 0) {
			dayOffset = dayOffset + 7;
		}
		startsOn = startsOn.plusDays(dayOffset);
		localDates.add(this.getData(repeatParams, startsOn));
		int maxCount = ParameterCache.getIntValue("PeroidMaxCount", 100);
		if (repeatParams.getEndtype() == 2) {// 设置次数
			if (repeatParams.getTimes() > maxCount) {
				throw new RuntimeException("周期最多允许生成" + maxCount + "次");
			}
			for (int i = 1; i < repeatParams.getTimes(); i++) {
				LocalDate nextDate = startsOn.plusWeeks(repeatParams.getPeriodFrequency());
				localDates.add(this.getData(repeatParams, nextDate));
				startsOn = nextDate;
			}
		} else {
			LocalDate endsOn = LocalDate.parse(repeatParams.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			endsOn = endsOn.plusDays(1);
			LocalDate nextDate = startsOn;
			while (nextDate.plusWeeks(repeatParams.getPeriodFrequency()).isBefore(endsOn)) {
				nextDate = nextDate.plusWeeks(repeatParams.getPeriodFrequency());
				localDates.add(this.getData(repeatParams, nextDate));
				if (localDates.size() > maxCount) {
					throw new RuntimeException("周期最多允许生成" + maxCount + "次");
				}
			}
		}
		return localDates;
	}

	/**
	 * 周期类型月
	 * 
	 * @description:
	 * @param repeatParams
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午10:18:37
	 * @modify:
	 */
	private List<Map<String, Object>> repeatByMonth(PeroidParams repeatParams) {
		List<Map<String, Object>> localDates = null;
		if (repeatParams.getRepeatEveryType() == 1) {// 周为单位，月的第几周
			localDates = this.repeatMonthByWeek(repeatParams);
		} else if (repeatParams.getRepeatEveryType() == 2) {// 天为单位，月的第几号
			localDates = this.repeatMonthByDay(repeatParams);
		} else {
			throw new RuntimeException("月周期类型，只支持以天或周规则");
		}
		return localDates;
	}

	/**
	 * 周期为月的按周生成
	 * 
	 * @description:
	 * @param repeatParams
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午10:55:52
	 * @modify:
	 */
	private List<Map<String, Object>> repeatMonthByWeek(PeroidParams repeatParams) {
		int maxCount = ParameterCache.getIntValue("PeroidMaxCount", 100);
		List<Map<String, Object>> localDates = new ArrayList<>();
		LocalDate startsOn = LocalDate.parse(repeatParams.getBeginTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		if (repeatParams.getEndtype() == 2) {// 设置次数
			// 计算第一天
			LocalDate first = this.findWeekDays(repeatParams.getDaySequence(), repeatParams.getMonthWeekTime(),
					startsOn);
			// 当前日期已过，从下个月开始
			if (first != null && first.isBefore(startsOn)) {
				startsOn = startsOn.plusMonths(1);
			}
			for (int i = 0; i < repeatParams.getTimes();) {
				LocalDate currentDay = this.findWeekDays(repeatParams.getDaySequence(), repeatParams.getMonthWeekTime(),
						startsOn);
				if (currentDay != null) {
					localDates.add(this.getData(repeatParams, currentDay));
					i++;
				}
				startsOn = startsOn.plusMonths(1);
				if (localDates.size() > maxCount) {
					throw new RuntimeException("周期最多允许生成" + maxCount + "次");
				}
			}
		} else {// 结束时间生成
			LocalDate endsOn = LocalDate.parse(repeatParams.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			endsOn = endsOn.plusDays(1);
			LocalDate nextDate = startsOn;
			while (nextDate.isBefore(endsOn)) {
				LocalDate currentDay = this.findWeekDays(repeatParams.getDaySequence(), repeatParams.getMonthWeekTime(),
						nextDate);
				// 判断当前日期是否在结束日期内
				if (currentDay == null) {
					nextDate = LocalDate.of(nextDate.getYear(), nextDate.getMonth(), 1).plusMonths(1);
				} else {
					if (currentDay.isBefore(endsOn)) {
						localDates.add(this.getData(repeatParams, currentDay));
					}
					nextDate = LocalDate.of(nextDate.getYear(), nextDate.getMonth(), 1).plusMonths(1);
				}
				if (localDates.size() > maxCount) {
					throw new RuntimeException("周期最多允许生成" + maxCount + "次");
				}
			}
		}
		return localDates;
	}

	/**
	 * 周期为月的按日生成，月的几号
	 * 
	 * @description:
	 * @param repeatParams
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午10:43:04
	 * @modify:
	 */
	private List<Map<String, Object>> repeatMonthByDay(PeroidParams repeatParams) {
		int maxCount = ParameterCache.getIntValue("PeroidMaxCount", 100);
		List<Map<String, Object>> localDates = new ArrayList<>();
		LocalDate startsOn = LocalDate.parse(repeatParams.getBeginTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		int startDay = startsOn.getDayOfMonth();
		// 几号
		int dayNum = repeatParams.getDaySequence();
		// 偏移天数
		int dayOffset = dayNum - startDay;
		// 获取初始值
		if (dayOffset > 0) {
			// 取本月值
			startsOn = startsOn.plusDays(dayOffset);
		} else if (dayOffset < 0) {
			// 取下月值
			startsOn = startsOn.plusDays(dayOffset).plusMonths(1);
		}
		localDates.add(this.getData(repeatParams, startsOn));
		if (repeatParams.getEndtype() == 2) {// 设置次数
			for (int i = 1; i < repeatParams.getTimes(); i++) {
				LocalDate date = startsOn.plusMonths(1);
				localDates.add(this.getData(repeatParams, date));
				startsOn = date;
				if (localDates.size() > maxCount) {
					throw new RuntimeException("周期最多允许生成" + maxCount + "次");
				}
			}
		} else {// 结束时间生成
			LocalDate endsOn = LocalDate.parse(repeatParams.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			endsOn = endsOn.plusDays(1);
			LocalDate nextDate = startsOn;
			while (nextDate.plusMonths(1).isBefore(endsOn)) {
				nextDate = nextDate.plusMonths(1);
				localDates.add(this.getData(repeatParams, nextDate));
				if (localDates.size() > maxCount) {
					throw new RuntimeException("周期最多允许生成" + maxCount + "次");
				}
			}
		}
		return localDates;
	}

	/**
	 * 得到当前时间月的第几周的周几日期
	 * 
	 * @description:
	 * @param monthWeekDay:周几
	 * @param monthWeekTimes：第几个周
	 * @param start
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日上午11:07:09
	 * @modify:
	 */
	private LocalDate findWeekDays(int monthWeekDay, int monthWeekTimes, LocalDate currentDate) {
		// 本月的第一天
		LocalDate firstday = LocalDate.of(currentDate.getYear(), currentDate.getMonth(), 1);
		// 本月的最后一天
		LocalDate lastDay = currentDate.with(TemporalAdjusters.lastDayOfMonth());
		// 第几个周
		int weekNum = 0;
		LocalDate currentday = null;
		for (; firstday.isBefore(lastDay); firstday = firstday.plusDays(1)) {
			// 周几
			int value = firstday.getDayOfWeek().getValue();
			if (value == monthWeekDay) {
				weekNum++;
				if (monthWeekTimes == -1) {// 最后一个周
					currentday = firstday;
				}
			}
			if (weekNum == monthWeekTimes) {
				currentday = firstday;
				break;
			}
		}
		return currentday;
	}

	/**
	 * @description:
	 * @return
	 * @author: donghang
	 * @date: 2020年10月29日下午1:47:25
	 * @modify:
	 */
	public Map<String, Object> getData(PeroidParams peroidParams, LocalDate startsOn) {
		Map<String, Object> value = new HashMap<>();
		StringBufferProxy name = new StringBufferProxy();
		switch (peroidParams.getPeriodType()) {
		case PeroidTypeEnum.Day: {
			value.put("name", name.appendSingle("{0}年{1}月{2}日", startsOn.getYear(), startsOn.getMonth().getValue(),
					startsOn.getDayOfMonth()));
			value.put("date", startsOn);
			break;
		}
		case PeroidTypeEnum.Week: {
			value.put("name", name.appendSingle("{0}年{1}月第{2}周", startsOn.getYear(), startsOn.getMonth().getValue(),
					startsOn.get(ChronoField.ALIGNED_WEEK_OF_MONTH)));
			value.put("date", startsOn);
			break;
		}
		case PeroidTypeEnum.Month: {
			value.put("name", name.appendSingle("{0}年{1}月", startsOn.getYear(), startsOn.getMonth().getValue()));
			value.put("date", startsOn);
			break;
		}
		}
		return value;
	}

	public static void main(String[] args) {
		PeroidParams repeatParams = new PeroidParams();
		// 1.周期类型为天的按结束日期生成
		repeatParams.setPeriodType(PeroidTypeEnum.Day);
		repeatParams.setBeginTime("2020-10-27");
		repeatParams.setEndTime("2020-12-27");
		repeatParams.setPeriodFrequency(2);
		repeatParams.setEndtype(2);
		PeroidRepeatService peroidRepeatService = new PeroidRepeatService();
		System.out.println("天：" + peroidRepeatService.getPeroidDays(repeatParams));
		// 2.周期类型为周的按结束日期生成
		repeatParams.setPeriodType(PeroidTypeEnum.Week);
		repeatParams.setBeginTime("2020-10-27");
		repeatParams.setEndTime("2020-12-27");
		repeatParams.setDaySequence(1);
		repeatParams.setPeriodFrequency(1);
		repeatParams.setEndtype(2);
		System.out.println("周：" + peroidRepeatService.getPeroidDays(repeatParams));
		// 3.周期类型为月的按结束日期生成
		repeatParams.setPeriodType(PeroidTypeEnum.Month);
		repeatParams.setBeginTime("2020-10-27");
		repeatParams.setEndTime("2020-12-27");
		repeatParams.setRepeatEveryType(2);
		repeatParams.setDaySequence(1);
		repeatParams.setPeriodFrequency(1);
		repeatParams.setEndtype(2);
		System.out.println("月第几天：" + peroidRepeatService.getPeroidDays(repeatParams));
		// 4.周期类型为月的按结束日期生成,每月第二周的周一
		repeatParams.setPeriodType(PeroidTypeEnum.Month);
		repeatParams.setBeginTime("2020-10-27");
		repeatParams.setEndTime("2020-12-27");
		repeatParams.setRepeatEveryType(1);
		repeatParams.setDaySequence(1);
		repeatParams.setPeriodFrequency(1);
		repeatParams.setEndtype(2);
		repeatParams.setMonthWeekTime(2);
		System.out.println("每月第二周的周一：" + peroidRepeatService.getPeroidDays(repeatParams));
		// 4.周期类型为月的按结束日期生成,每月最后一个周的周一
		repeatParams.setPeriodType(PeroidTypeEnum.Month);
		repeatParams.setBeginTime("2020-10-27");
		repeatParams.setEndTime("2020-12-31");
		repeatParams.setRepeatEveryType(1);
		repeatParams.setDaySequence(1);
		repeatParams.setPeriodFrequency(1);
		repeatParams.setEndtype(2);
		repeatParams.setMonthWeekTime(-1);
		System.out.println("每月最后一个周的周一：" + peroidRepeatService.getPeroidDays(repeatParams));
	}
}
